package com.example.mall.product.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;

// import org.apache.shiro.authz.annotation.RequiresPermissions;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.mall.product.entity.CategoryEntity;
import com.example.mall.product.service.CategoryService;
import com.example.mall.common.utils.PageUtils;
import com.example.mall.common.utils.R;



/**
 * 商品三级分类
 *
 * @author liaoen
 * @email laeg233@gmail.com
 * @date 2022-11-02 22:40:11
 */
@Slf4j
@RestController
@RequestMapping("product/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 树菜单
     */
    @RequestMapping("/list/tree")
    public R listCategoryTree(){
        List<CategoryEntity> categoryEntityList = categoryService.listCategoryTree();
        return R.ok().put("data", categoryEntityList);
    }

    /**
     * 列表
     */
    @RequestMapping("/list")
    // @RequiresPermissions("product:category:list")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = categoryService.queryPage(params);

        return R.ok().put("page", page);
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{catId}")
    // @RequiresPermissions("product:category:info")
    public R info(@PathVariable("catId") Long catId){
		CategoryEntity category = categoryService.getById(catId);

        return R.ok().put("category", category);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    // @RequiresPermissions("product:category:save")
    public R save(@RequestBody CategoryEntity category){
		categoryService.save(category);

        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    // @RequiresPermissions("product:category:update")
    public R update(@RequestBody CategoryEntity category){
        categoryService.updateById(category);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    // @RequiresPermissions("product:category:delete")
    public R delete(@RequestBody Long[] catIds){
		categoryService.removeMenusByIds(Arrays.asList(catIds));

        return R.ok();
    }

    /**
     * 测试写锁
     * @return R
     */
    @RequestMapping("/readLock")
    public R readLock() {
        String threadName = Thread.currentThread().getName();
        RReadWriteLock rReadWriteLock = redissonClient.getReadWriteLock("rw-lock");
        RLock lock = rReadWriteLock.readLock();
        lock.lock();
        String rwValue;
        try {
            log.info("[{}]线程加了读锁", threadName);
            Thread.sleep(10000);
            rwValue = stringRedisTemplate.opsForValue().get("rw");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("[{}]线程释放了读锁", threadName);
            }
        }
        return R.ok().put("readLock", "读锁-[" + rwValue + "]");
    }

    /**
     * 测试读锁
     * @return R
     */
    @RequestMapping("/writeLock")
    public R writeLock() {
        String threadName = Thread.currentThread().getName();
        RReadWriteLock rReadWriteLock = redissonClient.getReadWriteLock("rw-lock");
        RLock lock = rReadWriteLock.writeLock();
        lock.lock();
        String rwValue;
        try {
            log.info("[{}]线程加了写锁", threadName);
            Thread.sleep(10000);
            rwValue = UUID.randomUUID().toString();
            stringRedisTemplate.opsForValue().set("rw", rwValue);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("[{}]线程释放了写锁", threadName);
            }
        }
        return R.ok().put("writeLock", "写锁-[" + rwValue + "]");
    }

    /**
     * 测试闭锁
     * @return R
     */
    @RequestMapping("/countDownLunchAwait")
    public R countDownLunchAwait() {
        RCountDownLatch countDownLatch = redissonClient.getCountDownLatch("countDownLatchLock");
        countDownLatch.trySetCount(3L);
        try {
            log.info("裁判：各就位，预备......");
            countDownLatch.await();
            log.info("砰...开始...");
            return R.ok();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 测试闭锁
     * @return R
     */
    @RequestMapping("/countDownLunch")
    public R countDownLunch() {
        RCountDownLatch countDownLatch = redissonClient.getCountDownLatch("countDownLatchLock");
        countDownLatch.countDown();
        log.info("[{}号]准备就绪...", Thread.currentThread().getId());
        return R.ok();
    }

    /**
     * 测试信号量
     * @return R
     */
    @RequestMapping("/semaphoreIn")
    public R semaphoreIn() {
        RSemaphore semaphoreLock = redissonClient.getSemaphore("semaphoreLock");
        try {
//            boolean b = semaphoreLock.tryAcquire();
            semaphoreLock.acquire();
            log.info("[{}]一辆车占了一个车位", Thread.currentThread().getId());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return R.ok();
    }

    /**
     * 测试信号量
     * @return R
     */
    @RequestMapping("/semaphoreOut")
    public R semaphoreOut() {
        RSemaphore semaphoreLock = redissonClient.getSemaphore("semaphoreLock");
        semaphoreLock.release();
        log.info("一辆车开出了车位");
        return R.ok();
    }

}
